package netty.demo_01_simple;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import netty.demo_02_taskqueue.NettyServerHandlerTaskQ;

/**
 * Netty快速入门实例-TCP服务
 * 服务端
 *
 * @author chenyuan
 * @date 2020/11/6 17:38
 */
public class NettyServer {
	public static void main(String[] args) throws InterruptedException {
		// 创建 BossGroup 和 WorkerGroup
        /*
            说明
            1. 创建两个线程组 BossGroup 和 WorkerGroup
            2. BossGroup 只处理连接请求
            3. WorkerGroup 处理真正客户端的业务
            4. 运行时，这两个都是无限循环
            5. BossGroup 和 WorkerGroup 含有的子线程数（NioEventLoop）默认为 CPU 核数*2
         */
		EventLoopGroup bossGroup = new NioEventLoopGroup(1);
		EventLoopGroup workerGroup = new NioEventLoopGroup(4);

		// 进行异常处理，try - catch
		try {
			// 创建 服务端 启动对象，并配置参数
			ServerBootstrap bootstrap = new ServerBootstrap();
			// 使用链式编程进行配置参数
			bootstrap.group(bossGroup, workerGroup)// 设置两个线程组
					.channel(NioServerSocketChannel.class)// 使用 NioServerSocketChannel 作为服务器的通道实现
					.option(ChannelOption.SO_BACKLOG, 128)// 设置线程队列等待连接的个数
					.childOption(ChannelOption.SO_KEEPALIVE, true)// 设置连接保持活动连接状态
					.childHandler(new ChannelInitializer<SocketChannel>() {// 给 workerGroup 的 NioEventLoop 对应的管道（Pipeline）设置处理器
						// 创建一个通道初始化对象

						/**
						 * 向 workerGroup 对应的 管道（Pipeline） 设置处理器
						 *
						 * @param socketChannel
						 * @throws Exception
						 */
						@Override
						protected void initChannel(SocketChannel socketChannel) throws Exception {
							System.out.println("当前客户对应的 SocketChannel 的 HashCode ：" + socketChannel.hashCode());

//                            socketChannel.pipeline()// 获得 这个 socketChannel 对应的 Pipeline
//                                    .addLast(new NettyServerHandler());// 把自定义的 Handler 添加到 管道

							socketChannel.pipeline().addLast(new NettyServerHandlerTaskQ());
						}
					});
			System.out.println("服务器准备好了……");
			// 绑定一个端口，并且同步。生成了一个 ChannelFuture 对象
			// 这里就已经启动了服务器
			ChannelFuture channelFuture = bootstrap.bind(6668).sync();
			// 给一个 ChannelFuture 注册监听器，来监控我们关系的事件
			channelFuture.addListener(new ChannelFutureListener() {
				@Override
				public void operationComplete(ChannelFuture channelFuture) throws Exception {
					if (channelFuture.isSuccess()) {
						System.out.println("监听端口 6668 成功");
					} else {
						System.out.println("监听端口 6668 失败");
					}
				}
			});


			// 对 关闭通道 进行监听
			// 这里只是监听，只有关闭通道时才进行处理，这句话不是直接关闭了通道
			channelFuture.channel().closeFuture().sync();
		} finally {
			bossGroup.shutdownGracefully();
			workerGroup.shutdownGracefully();
		}


	}
}
